/**
 * Alipay.com Inc. Copyright (c) 2004-2018 All Rights Reserved.
 */
package com.yeyks.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yeyks.base.Arguments;
import com.yeyks.dal.dao.AccountInfoMapper;
import com.yeyks.dal.dao.HotelInfoMapper;
import com.yeyks.dal.dao.UserInfoMapper;
import com.yeyks.dal.domain.AccountInfo;
import com.yeyks.dal.domain.UserInfo;
import com.yeyks.exception.PermissionInvalidException;
import com.yeyks.exception.ServiceException;
import com.yeyks.exception.SmsSendException;
import com.yeyks.exception.TokenInvalidException;
import com.yeyks.model.Ajax.AjaxResponseBody;
import com.yeyks.model.em.AccountType;
import com.yeyks.model.em.ResponseStatus;
import com.yeyks.service.AccountService;
import com.yeyks.service.MessageService;
import com.yeyks.service.SmsHistoryService;
import com.yeyks.service.SmsService;
import com.yeyks.util.DateUtils;
import com.yeyks.util.TextValidator;
import com.yeyks.util.Utility;
import com.yeyks.exception.PermissionInvalidException;
import com.yeyks.exception.SmsSendException;
import com.yeyks.exception.TokenInvalidException;
import com.yeyks.model.Ajax.AjaxResponseBody;
import com.yeyks.model.em.AccountType;
import com.yeyks.model.em.ResponseStatus;
import com.yeyks.service.AccountService;
import com.yeyks.service.MessageService;
import com.yeyks.service.SmsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 账户管理接口
 * @author Beacon
 * @version $Id: AccountController.java, v 0.1 2018年07月30日 17:18 Beacon Exp $
 */
@Api(tags = "001001000_account|&账户", description = "账户模块接口")
@Slf4j
@RestController
@RequestMapping(value = "/ajax/account")
public class AccountController {

    @Autowired
    AccountService accountService;

    @Autowired
    AccountInfoMapper accountInfoMapper;

    @Autowired
    HotelInfoMapper hotelInfoMapper;

    @Autowired
    SmsService smsService;

    @Autowired
    MessageService messageService;

    @Autowired
    UserInfoMapper userInfoMapper;

    @Autowired
    private SmsHistoryService smsHistoryService;

    // 万能手机号，这个手机号不管输入什么验证码，都能通过验证码检测
    private final String magicPhone = "15757115842";
    /**
     * 获得短信验证用于注册
     * @param phone 需要创建账号的电话号码
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/getVerifyCode", method = RequestMethod.POST)
    public ResponseEntity<?> getVerifyCode(
            @RequestParam(name = "phone", defaultValue = "", required = true) String phone
    ) {
        AjaxResponseBody response = new AjaxResponseBody();
        if (phone == null) {
            // 2.输入的手机格式不对时，系统给出提示【手机格式不正确】。
            response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDPHONE.getCode());
            response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDPHONE.getMsg());
        } else {
            try {
                smsService.sendSmsForSignup(phone);
                response.setBody(true);
                response.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
                response.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
            } catch (SmsSendException e) {

                if (e.getWait() == 0) {
                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_SMSINVALID.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_SMSINVALID.getMsg());
                } else {
                    // 其它写入失败
                    Map<String, Object> map = new HashMap<>();
                    map.put("wait", e.getWait());
                    response.setBody(map);
                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_SMSWAIT.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_SMSWAIT.getMsg());
                }
            } catch (ServiceException e) {
                // 其它写入失败
                response.setCode(-1);
                response.setMsg(e.getMessage());
            }catch (Throwable e) {
                // 其它写入失败
                response.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
                response.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL.getMsg());
            }
        }

        return ResponseEntity.ok(response);
    }


    /**
     * 验证发送的注册短信是否正确
     * @param phone
     * @param code
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/verifyCode", method = RequestMethod.POST)
    public ResponseEntity<?> verifyCode(
            @RequestParam(name = "phone", defaultValue = "", required = true) String phone,
            @RequestParam(name = "code", defaultValue = "", required = true) String code
    ) {
        AjaxResponseBody response = new AjaxResponseBody();
        try {
            response.setBody(smsService.verifySmsForSignup(phone, code));
            response.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
            response.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
        } catch (Throwable e) {
            // 其它写入失败
            response.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
            response.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL.getMsg());
        }
        return ResponseEntity.ok(response);
    }

    protected boolean checkRegParam(AccountInfo param, AjaxResponseBody responseBody) {

        if ((param.getPhone() == null || param.getPhone().isEmpty()) &&
                (param.getUsername() == null || param.getUsername().isEmpty())) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDNAME.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDNAME.getMsg());
        }

        if (Arguments.notEmpty(param.getPhone()) && TextValidator.MOBILE.boolCheck(param.getPhone())) {
            // 2.输入的手机格式不对时，系统给出提示【手机格式不正确】。
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDPHONE.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDPHONE.getMsg());
        } else if (param.getPassword() == null ||
                param.getPassword().length() < 6 ||
                param.getPassword().length() > 16) {
            // 3.输入的密码过长或过短时，系统给出提示【密码的有效长度为6-16位】。
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDPWD.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDPWD.getMsg());
            return false;
        } else if (Arguments.notEmpty(param.getUsername()) &&
                param.getUsername().length() > 32) {
            // 4.输入的登陆用户名不对
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDUSERNAME.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDUSERNAME.getMsg());
            return false;
        }

        return true;
    }
    /**
     * 注册账号接口
     * @param param 创建账号参数
     * @param token
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/reg", method = RequestMethod.POST)
    public ResponseEntity<?> reg(
            @RequestParam(name = "token", defaultValue = "", required = true) String token,
            AccountInfo param
    ){
        AjaxResponseBody response = new AjaxResponseBody();

        try {
            if (param.getType() == AccountType.Administrator) {
                List<AccountInfo> accountInfos = accountInfoMapper.selectByType(AccountType.Administrator);
                if (accountInfos != null && accountInfos.size() != 0) {
                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_EXISTED.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_EXISTED.getMsg());
                    return ResponseEntity.ok(response);
                }
            } else {
                AccountInfo operatorInfo = accountService.token2AccountInfo(token);
                switch (param.getType()) {
                    case AccountType.HotelManager://酒店(只有城市运营商才能建立酒店)
                        if (operatorInfo.getType() != AccountType.CityManager) {
                            throw new PermissionInvalidException();
                        }
                        param.setParentId(operatorInfo.getId());
                        break;
                    case AccountType.CityManager://城市运营商(只有市代理才能建立城市运营商)
                        if (operatorInfo.getType() != AccountType.CityAgent) {
                            throw new PermissionInvalidException();
                        }
                        param.setParentId(operatorInfo.getId());
                        break;
                    case AccountType.CityAgent://市代理(只有省代理才能建立市代理)
                        if (operatorInfo.getType() != AccountType.BranchManager) {
                            throw new PermissionInvalidException();
                        }
                        param.setParentId(operatorInfo.getId());
                        break;
                    case AccountType.BranchManager://省代理(只有总公司才能建立省代理)
                        if (operatorInfo.getType() != AccountType.Administrator) {
                            throw new PermissionInvalidException();
                        }
                        param.setParentId(operatorInfo.getId());
                        break;
                    case AccountType.User://用户
                        // TODO:不允许直接从该入口注册普通用户账号
                        throw new PermissionInvalidException();
                    default:
                        throw new PermissionInvalidException();

                }
            }

            if (checkRegParam(param, response)) {

//                List<AccountInfo> existAccount = accountInfoMapper.selectByPhoneOrUsername(param.getPhone(), param.getUsername());
                List<AccountInfo> existAccount = accountInfoMapper.selectByPhoneOrUsername(null, param.getUsername());

                if (param.getValid() == null) {
                    param.setValid(true);
                }

                if (existAccount == null || existAccount.isEmpty()) {
                    accountInfoMapper.insertReturnId(param);

                    if (param.getType() != AccountType.User) {
                        messageService.createAccount(param.getId());
                    }

                    // 如果写入成功，返回用户信息
                    response.setBody(param);
                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
                } else {
                    // 已存在账户，获得对应ID
                    param = new AccountInfo();
                    param.setId(existAccount.get(0).getId());
                    response.setBody(param);

                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_EXISTED_TWO.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_EXISTED_TWO.getMsg());
                }
            }
        } catch (DuplicateKeyException e) {
            // 已经存在这个电话号码，写入失败
            response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_EXISTED_TWO.getCode());
            response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_EXISTED_TWO.getMsg());
        } catch (Throwable e) {
            // 其它写入失败
            response.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
            response.setMsg(e.getMessage());
        }
        return ResponseEntity.ok(response);
    }

    protected void packLoginResult(AccountInfo accountInfo, AjaxResponseBody responseBody) {

        // 用户ID生成Token
        String token = accountService.userId2Token(accountInfo.getId());

        // 生成结果
        Map<String, Object> res = new HashMap<>();
        res.put("user_info", accountInfo);
        res.put("token", token);
        responseBody.setBody(res);
    }

    protected void packLoginResultV2(Integer id, Object object, AjaxResponseBody responseBody) {

        // 用户ID生成Token
        String token = accountService.userId2Token(id);

        // 生成结果
        Map<String, Object> res = new HashMap<>();
        res.put("user_info", object);
        res.put("token", token);
        responseBody.setBody(res);
    }
    /**
     * 用户登录
     * @param accountInfo
     * @return
     */
    @ApiIgnore
    @ApiOperation(value = "001001001_account_add|&用户登录", notes = "用户登录")
    @RequestMapping(value="/login", method = RequestMethod.POST)
    public ResponseEntity<?> login(
            AccountInfo accountInfo,
            @RequestParam(name = "code", defaultValue = "", required = true) String code
    ){
        log.info("参数{}{}", accountInfo, code);
        AjaxResponseBody response= new AjaxResponseBody();

        if (code == null || code.isEmpty()) {

            List<AccountInfo> result = null;
            //用户的话使用手机号密码登陆
            if (accountInfo.getType() != null && accountInfo.getType().equals(AccountType.User)) {
                if (Arguments.notEmpty(accountInfo.getPhone())) {
                    result = accountInfoMapper.selectUsePhonePwd(accountInfo.getPhone(), accountInfo.getPassword());
                }
            } else {
                if (Arguments.notEmpty(accountInfo.getUsername())) {
                    result = accountInfoMapper.selectUseUsernamePwd(accountInfo.getUsername(), accountInfo.getPassword());
                }
            }
            if (result != null && result.size() != 0) {
                packLoginResult(result.get(0), response);
                response.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
                response.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
            } else {
                response.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_NOT_FOUND.getCode());
                response.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_NOT_FOUND.getMsg());
            }
        } else {

            if (smsService.verifySmsForSignup(accountInfo.getPhone(), code) ||
                    magicPhone.compareToIgnoreCase(accountInfo.getPhone()) == 0) {
                // 查找用户的所有信息
                AccountInfo accInfo = accountInfoMapper.selectUsePhone(accountInfo.getPhone());

                if (accInfo != null) {

                    packLoginResult(accInfo, response);

                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
                } else {
                    // 不保存密码
                    if (accountInfo.getNickname() == null) {
                        accountInfo.setNickname("User_" + UUID.randomUUID().toString().substring(0, 7));
                    }
                    accountInfo.setPassword(null);
                    accountInfo.setType(AccountType.User);
                    accountInfoMapper.insertReturnId(accountInfo);

                    packLoginResult(accountInfo, response);

                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_S_NEWACCOUNT.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_S_NEWACCOUNT.getMsg());
                }
            } else {
                response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_INVALIDCODE.getCode());
                response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_INVALIDCODE.getMsg());
            }
        }
        return ResponseEntity.ok(response);
    }

    /**
     * 获得账户的完整信息
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/getInfo", method = RequestMethod.POST)
    public ResponseEntity<?> getInfo(
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(name = "token", defaultValue = "", required = true) String token,
            AccountInfo param
    ){
        AjaxResponseBody responseBody = new AjaxResponseBody();
        try {
            AccountInfo operatorInfo = accountService.token2AccountInfo(token);

            AccountInfo accountInfo = null;
            if (param.getId() != null && param.getId() != 0) {
                accountInfo = accountInfoMapper.selectByPrimaryKey(param.getId());
                if (operatorInfo.getType() >= accountInfo.getType()) {
                    throw new PermissionInvalidException();
                }
            } else {
                accountInfo = accountService.token2AccountInfo(token);
            }

            responseBody.setBody(accountInfo);
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
        } catch (PermissionInvalidException e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_PERMISSION.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_PERMISSION.getMsg());
        } catch (TokenInvalidException e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getMsg());
        } catch (Throwable e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(e.getMessage());
        }

        return ResponseEntity.ok(responseBody);
    }

    /**
     * 获得用户的完整信息（拆分用户表时新加数据）
     *
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/user/getInfo", method = RequestMethod.POST)
    public ResponseEntity<?> getInfoV2(@RequestParam(name = "token", defaultValue = "", required = true) String token,
                                       @RequestParam(name = "id") Integer id
    ) {
        AccountInfo operatorInfo = accountService.token2AccountInfoV2(token);
        if (operatorInfo.getType() >= AccountType.User) {
            throw new ServiceException("当前用户访问权限不足");
        }
        UserInfo userInfo = userInfoMapper.selectByPrimaryKey(id);
        if (userInfo == null) {
            throw new ServiceException("该用户不存在");
        }
        return ResponseEntity.ok(AjaxResponseBody.success(userInfo));
    }

    @ApiIgnore
    @RequestMapping(value = "/setInfo", method = RequestMethod.POST)
    public ResponseEntity<?> setInfo(
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(name = "token", defaultValue = "", required = true) String token,
            @RequestParam(name = "force", defaultValue = "false", required = true) Boolean force,
            AccountInfo param
    ){
        AjaxResponseBody responseBody = new AjaxResponseBody();
        try {

            AccountInfo operatorInfo = accountService.token2AccountInfo(token);
            if (param.getId() == null || param.getId() == 0) {
                // 操作自己本身账户
                param.setId(operatorInfo.getId());
            }

            AccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(param.getId());
            if (accountInfo == null) {
                throw new Exception("account not exist");
            } else if (operatorInfo.getType() > accountInfo.getType()) {
                throw new PermissionInvalidException();
            } else if (operatorInfo.getType() == accountInfo.getType()) {
                if (operatorInfo.getId().intValue() != accountInfo.getId().intValue()) {
                    throw new PermissionInvalidException();
                }
            }

            // 某些信息无法修改
            param.setType(accountInfo.getType());
            param.setParentId(accountInfo.getParentId());
            if (param.getPhone() != null && !param.getPhone().equals(accountInfo.getPhone())) {
                List<AccountInfo> accountInfos = accountInfoMapper.selectByPhoneOrUsername(param.getPhone(), null);

                if (!accountInfos.isEmpty()) {
                    responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_EXIST_PHONE.getCode());
                    responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_EXIST_PHONE.getMsg());

                    return ResponseEntity.ok(responseBody);
                }
            }
            param.setPassword(accountInfo.getPassword());
            if (operatorInfo.getType() != AccountType.Administrator &&
                    operatorInfo.getType() != AccountType.BranchManager) {
                param.setUsername(accountInfo.getUsername());
            }

            // 填充原始字段
            if (!force) {
                Field[] fields = AccountInfo.class.getDeclaredFields();
                for (Field field : fields) {
                    String fieldName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                    Method getMethod = AccountInfo.class.getMethod("get" + fieldName);
                    Method setMethod = AccountInfo.class.getMethod("set" + fieldName, field.getType());

                    if (getMethod.invoke(param) == null) {
                        setMethod.invoke(param, getMethod.invoke(accountInfo));
                    }
                }
            }

            int result = accountInfoMapper.updateByPrimaryKey(param);
            if (result == 0) {
                throw new Exception("dal exception");
            }

            responseBody.setBody(result);
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
        } catch (TokenInvalidException e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getMsg());
        } catch (Throwable e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL.getMsg());
        }

        return ResponseEntity.ok(responseBody);
    }

    @ApiIgnore
    @RequestMapping(value = "/modifyPassword", method = RequestMethod.POST)
    public ResponseEntity<?> modifyPassword(
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(name = "token", defaultValue = "", required = true) String token,
            @RequestParam(name = "origPwd", defaultValue = "", required = true) String origPwd,
            AccountInfo param
    ){
        AjaxResponseBody responseBody = new AjaxResponseBody();
        try {
            if (param.getPassword() == null || param.getPassword().isEmpty()) {
                throw new Exception("The contents of the password cannot be empty");
            }

            AccountInfo operatorInfo = accountService.token2AccountInfo(token);
            AccountInfo origAccountInfo;
            if (param.getId() == null || param.getId() == 0 || param.getId().equals(operatorInfo.getId())) {
                param.setId(operatorInfo.getId());
                origAccountInfo = accountInfoMapper.selectByPrimaryKey(param.getId());
            } else {
                origAccountInfo = accountInfoMapper.selectByPrimaryKey(param.getId());
                if (origAccountInfo.getType() <= operatorInfo.getType() &&
                        operatorInfo.getId() != origAccountInfo.getId()) {
                    throw new PermissionInvalidException();
                }
            }

            if (!origPwd.isEmpty() && !origPwd.equals(origAccountInfo.getPassword())) {
                responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_ORIG_PASSWORD_WRONG.getCode());
                responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_ORIG_PASSWORD_WRONG.getMsg());
                return ResponseEntity.ok(responseBody);
            }

            int rec = accountInfoMapper.modifyPasswordById(param.getId(), param.getPassword());

            if (rec != 0) {
                responseBody.setBody(param);
            } else {
                throw new Exception("Updated 0 item");
            }

            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
        } catch (TokenInvalidException e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getMsg());
        } catch (Throwable e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(e.getMessage());
        }

        return ResponseEntity.ok(responseBody);
    }

    /**
     * 上级修改密码
     * @param token
     * @param newPwd
     * @param id
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/updatePassword", method = RequestMethod.POST)
    public ResponseEntity<?> updatePassword(
            @RequestParam(name = "token") String token,
            @RequestParam(name = "newPwd") String newPwd,
            @RequestParam(name = "id") Integer id) {
        checkoutParam(token, newPwd, id);
        AccountInfo operatorInfo = accountService.token2AccountInfoV2(token);
        AccountInfo origAccountInfo = accountInfoMapper.selectByPrimaryKey(id);
        if (operatorInfo.getType() != null
                && origAccountInfo.getType() != null
                && operatorInfo.getType() > origAccountInfo.getType()) {
            throw new ServiceException("您无权修改密码");
        }
        int rec = accountInfoMapper.modifyPasswordById(id, newPwd);

        if (rec == 0) {
            throw new ServiceException("修改数据失败");
        }
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    private void checkoutParam(String token, String newPwd, Integer id) {
        if (Arguments.isEmpty(token) || Arguments.isEmpty(newPwd) || Arguments.isNullOrZero(id)) {
            throw new ServiceException("参数传递有误");
        }
        if (newPwd.length() < 6 || newPwd.length() > 16) {
            // 3.输入的密码过长或过短时，系统给出提示【密码的有效长度为6-16位】。
            throw new ServiceException("密码的有效长度为6-16位");
        }
    }


    /**
     * 根据条件查询当前用户下账号的个数
     * @param request
     * @param response
     * @param token
     * @param child
     * @param dtStart
     * @param dtEnd
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = {"/count"}, method = {RequestMethod.POST, RequestMethod.GET})
    public ResponseEntity<?> count(
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(name = "token", defaultValue = "", required = true) String token,
            @RequestParam(name = "child", defaultValue = "false", required = true) Boolean child, // 是否只搜索
            @RequestParam(name = "dtStart", defaultValue = "0", required = true) Long dtStart,
            @RequestParam(name = "dtEnd", defaultValue = "0", required = true) Long dtEnd
    ){
        AjaxResponseBody responseBody = new AjaxResponseBody();
        try {

            AccountInfo operatorInfo = accountService.token2AccountInfo(token);
            String start = null;
            if (dtStart != null) {
                start = DateUtils.stampToDate(String.valueOf(dtStart));
            }
            String end = null;
            if (dtEnd != null) {
                end = DateUtils.stampToDate(String.valueOf(dtEnd));
            }
//            int count = accountInfoMapper.countOfChildren((child ? operatorInfo.getId() : null),
//                    dtStart == 0 ? null : new Date(dtStart),
//                    dtEnd == 0 ? null : new Date(dtEnd));
            int count = accountInfoMapper.countOfChildren((child ? operatorInfo.getId() : null),
                    start == null ? null : DateUtils.toDateTime(start),
                    end == null ? null : DateUtils.toDateTime(end));

            responseBody.setBody(count);
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
        } catch (TokenInvalidException e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getMsg());
        } catch (Throwable e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL.getMsg());
        }

        return ResponseEntity.ok(responseBody);
    }

    /**
     * 根据指定条件查询账号信息
     * @param request
     * @param response
     * @param token
     * @param child
     * @param type
     * @param valid
     * @param keyword
     * @param area
     * @param pageNum
     * @param pageSize
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = {"/listChild", "/list"}, method = {RequestMethod.POST, RequestMethod.GET})
    public ResponseEntity<?> listChild(
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(name = "token", defaultValue = "", required = true) String token,
            @RequestParam(name = "child", defaultValue = "false", required = true) Boolean child, // 是否只搜索子账户（超管有效）
            @RequestParam(name = "type", defaultValue = "0", required = true) Integer type,       // 需要过滤的类型
            @RequestParam(name = "valid", defaultValue = "", required = true) Boolean valid,      // valid字段限制
            @RequestParam(name = "keyword", defaultValue = "", required = true) String keyword,   // 关键字
            @RequestParam(name = "area", defaultValue = "", required = true) String area,         // 搜索区域
            @RequestParam(name = "pageNum", defaultValue = "0", required = true) Integer pageNum, // 页号
            @RequestParam(name = "pageSize", defaultValue = "0", required = true) Integer pageSize// 页尺
    ){
        AjaxResponseBody responseBody = new AjaxResponseBody();
        try {

            Integer offset = null, maxrow = null;
            if (pageNum != 0 && pageSize != 0) {
                offset = (pageNum - 1) * pageSize;
                maxrow = pageSize;
            }

            AccountInfo operatorInfo = accountService.token2AccountInfo(token);
            List<AccountInfo> accountInfoList = null;
            int count = 0;
            if (operatorInfo.getType() == AccountType.BranchManager ||
                    operatorInfo.getType() == AccountType.Administrator ||
                    operatorInfo.getType() == AccountType.CityAgent) {
                if (type != null && type != 0) {
                    accountInfoList = accountInfoMapper.selectByTypeValidKeyword(
                            type, valid, keyword, area, offset, maxrow);
                    count = accountInfoMapper.selectByTypeValidKeywordCount(
                            type, valid, keyword, area);
                } else {
                    accountInfoList = accountInfoMapper.selectChildByValidKeyword(
                            child ? operatorInfo.getId() : null, valid, keyword, area, offset, maxrow);
                    count = accountInfoMapper.selectChildByValidKeywordCount(
                            child ? operatorInfo.getId() : null, valid, keyword, area);
                }
            } else {
                responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_PERMISSION.getCode());
                responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_PERMISSION.getMsg());
                return ResponseEntity.ok(responseBody);
            }


            List<JSONObject> jsonObjects = new ArrayList<>();
            for (AccountInfo info : accountInfoList) {
                JSONObject jsonObject = (JSONObject) JSON.toJSON(info);
                int countChildren = accountInfoMapper.countOfChildren(info.getId(), null, null);
                jsonObject.put("childCount", countChildren);
                if (info.getType() == AccountType.CityAgent) {
                    int countGrandchildren = accountInfoMapper.countOfGrandchildren(info.getId(), null, null);
                    jsonObject.put("grandchildrenCount", countGrandchildren);
                }
                if (info.getType() == AccountType.BranchManager) {
                    int countGrandchildren = accountInfoMapper.countOfGrandchildchildren(info.getId(), null, null);
                    jsonObject.put("grandchildrenCount", countGrandchildren);
                }

                jsonObjects.add(jsonObject);
            }

            responseBody.addMapBody("list", jsonObjects);

            responseBody.addMapBody("count", count);

            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
        } catch (TokenInvalidException e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getMsg());
        } catch (Throwable e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL.getMsg());
        }

        return ResponseEntity.ok(responseBody);
    }

    /**
     * 根据指定条件删除账户
     * @param request
     * @param response
     * @param token
     * @param accountInfo
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/del", method = RequestMethod.POST)
    public ResponseEntity<?> del(
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(name = "token", defaultValue = "", required = true) String token,
            AccountInfo accountInfo
    ){
        AjaxResponseBody responseBody = new AjaxResponseBody();

        try {
            AccountInfo operatorInfo = accountService.token2AccountInfo(token);

            AccountInfo targetInfo = accountInfoMapper.selectByPrimaryKey(accountInfo.getId());

            if (targetInfo.getType() == AccountType.User &&
                    operatorInfo.getType() != AccountType.Administrator) {
                throw new PermissionInvalidException();
            } else if (operatorInfo.getType() >= targetInfo.getType()) {
                throw new PermissionInvalidException();
            } else if (targetInfo.getType() == AccountType.HotelManager &&
                    operatorInfo.getType() == AccountType.CityManager &&
                    targetInfo.getParentId().longValue() != operatorInfo.getId().longValue()) {
                throw new PermissionInvalidException();
            }  else if (targetInfo.getType() == AccountType.CityManager &&
                    operatorInfo.getType() == AccountType.CityAgent &&
                    targetInfo.getParentId().longValue() != operatorInfo.getId().longValue()) {
                throw new PermissionInvalidException();
            }

            int rec = accountInfoMapper.deleteByPrimaryKey(accountInfo.getId());
            if (rec == 0) {
                throw new Exception("deleted 0 row.");
            }

            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
        } catch (TokenInvalidException e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_TOKEN.getMsg());
        } catch (PermissionInvalidException e) {
            responseBody.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_PERMISSION.getCode());
            responseBody.setMsg(com.yeyks.model.em.ResponseStatus.RS_FAIL_INVALID_PERMISSION.getMsg());
        } catch (Throwable e) {
            responseBody.setCode(ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(e.getMessage());
        }

        return ResponseEntity.ok(responseBody);
    }

    private void checkToken(String token, Integer createTime, Integer province) {
        if (Arguments.isEmpty(token)) {
            throw new ServiceException("token不能为空");
        }
        if (createTime != null && province != null) {
            throw new ServiceException("排序参数有误");
        }
    }

    /**
     * 获取用户token
     *
     * @param userId
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/test/getToken", method = RequestMethod.POST)
    public AjaxResponseBody testGetToken(@RequestParam(name = "userId") Integer userId) {
        return AjaxResponseBody.success(accountService.userId2Token(userId));
    }

    /**
     * 查询出来状态为6的（即用户），将用户迁移到用户表中
     *
     * @return
     */
    @ApiIgnore
    @GetMapping(value = "/test/change/user")
    public AjaxResponseBody testChangeUser() {
        accountService.testChangeUser();
        return AjaxResponseBody.success();
    }

    /**
     * 查询城市运营商
     * @param token  token
     * @param valid  是否有效(默认有效)
     * @param keyword   关键字
     * @param area   省名称
     * @param pageNum   当前页 （默认1）
     * @param pageSize  页码 （默认10）
     * @param createTime 按照创建时间排序，0降序，1升序
     * @param province 按照省排序，0降序，1升序
     * @return
     */
    @ApiIgnore
    @PostMapping(value = {"/cityAgent/list"})
    public ResponseEntity<?> cityAgentList(@RequestParam(name = "token") String token,
            @RequestParam(name = "valid", required = false) Boolean valid,
            @RequestParam(name = "keyword", required = false) String keyword,
            @RequestParam(name = "area", required = false) String area,
            @RequestParam(name = "createTime", required = false) Integer createTime,
            @RequestParam(name = "province", required = false) Integer province,
            @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
            @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize
    ){
        checkToken(token, createTime, province);
        if (createTime == null && province == null) {
            createTime = 0;//默认按照创建时间倒叙
        }
        AccountInfo operatorInfo = accountService.token2AccountInfoV2(token);
        if (operatorInfo.getType() == null) {
            throw new ServiceException("当前用户权限不足");
        }
        //count和list
        Map<String, Object> map;
        //总公司查询所有的城市代理商
        if (operatorInfo.getType() == AccountType.Administrator) {
            map = accountService.cityAgentList(valid, area, keyword, operatorInfo.getId(), pageNum, pageSize, operatorInfo.getType(), createTime, province);
        } else if (operatorInfo.getType() == AccountType.BranchManager) {//分公司查询所有的城市代理商
            map = accountService.cityAgentList(valid, area, keyword, operatorInfo.getId(), pageNum, pageSize, operatorInfo.getType(), createTime, province);
        } else if (operatorInfo.getType() == AccountType.CityAgent) {//市代理查询所有的城市代理商
            map = accountService.cityAgentList(valid, area, keyword, operatorInfo.getId(), pageNum, pageSize, operatorInfo.getType(), createTime, province);
        } else {
            throw new ServiceException("当前用户权限不足");
        }

        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

}